package org.libtiff.jai.codecimpl;

import org.libtiff.jai.codec.XTIFFTileCodecImpl;
import org.libtiff.jai.codec.XTIFFTileCodec;
import org.libtiff.jai.codec.XTIFFEncodeParam;
import org.libtiff.jai.codec.XTIFF;
import org.libtiff.jai.util.JaiI18N;
import java.awt.Rectangle;


/**
 * This codec encapsulates all the logic for the default TIFF
 * "packbits" bit-packing codec algorithm.
 */
public class XTIFFPackTileCodec extends XTIFFTileCodecImpl {

    public XTIFFPackTileCodec() {
    }

    public XTIFFTileCodec create() {
	return new XTIFFPackTileCodec(); 
    }

    public boolean canEncode() {return false;}

    public void register() {
	register(XTIFF.COMPRESSION_PACKBITS);
    }

	/**
	 * encode the tile into bpixels and return the byte size
	 * (uncompressed packing algorithm). The padding has already
	 * been done, so we may safely assume that pixels is exactly
	 * rows by cols by numBands ints.
	 */
	
    public int encodeTilePixels(int[] pixels,Rectangle newRect,byte[] bpixels)
    {
	    return 0;
    }

	/**
	 * Decode a rectangle of pixels
	 */
    public void decodeTilePixels(byte[] input,Rectangle newRect,byte[] bdata) {

		if (bitsPerSample[0] == 8) {
			decodePackbits(input, unitsInThisTile, bdata);
		} else if (bitsPerSample[0] == 4) {
			// Since the decompressed data will still be packed 
			// 2 pixels into 1 byte, calculate bytesInThisTile
			int bytesInThisTile;
			if ((newRect.width % 8) == 0) {
			    bytesInThisTile =(newRect.width/2) * newRect.height;
			} else {
			    bytesInThisTile = (newRect.width/2 + 1) * 
				newRect.height;
			}
			
			decodePackbits(input, bytesInThisTile, bdata);
		}
    }

	/**
	 * Decode a rectangle of pixels
	 */
    public void decodeTilePixels(byte[] input,Rectangle newRect,short[] sdata) {
			int bytesInThisTile = unitsInThisTile * 2;
			byte byteArray[] = new byte[bytesInThisTile];
			decodePackbits(input, bytesInThisTile, byteArray);
			unpackShorts(byteArray, sdata, 
					       unitsInThisTile);
    }


    // Uncompress packbits compressed image data.
    private byte[] decodePackbits(byte data[], int arraySize, byte[] dst) {

	if (dst == null) {
	    dst = new byte[arraySize];
	}

	int srcCount = 0, dstCount = 0;
	byte repeat, b;

	try {
	    
	    while (dstCount < arraySize) {
		
		b = data[srcCount++];
		
		if (b >= 0 && b <= 127) {
		    
		    // literal run packet
		    for (int i=0; i<(b + 1); i++) {
			dst[dstCount++] = data[srcCount++];
		    }
		    		    
		} else if (b <= -1 && b >= -127) {
		    
		    // 2 byte encoded run packet
		    repeat = data[srcCount++];
		    for (int i=0; i<(-b + 1); i++) {
			dst[dstCount++] = repeat;
		    }
		    
		} else {
		    // no-op packet. Do nothing
		    srcCount++;
		}
	    }
	} catch (java.lang.ArrayIndexOutOfBoundsException ae) {
	    throw new RuntimeException(JaiI18N.getString("XTIFFImageDecoder10"));
	}

	return dst;
    }
}
